package j2EE.dispatcher.impl;

import j2EE.dispatcher.Dispatcher;
import j2EE.doaction.Action;
import org.springframework.util.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.IOException;
import java.io.InputStream;

/**
 *  这是调度器。基于所请求的URL映射的。因为我们的所有的视图都是在他们的请求中使用了“/pages/workflow”, 该 前端控制器 把这些请求映射到WorkflowDispatcher类的一个实现。
 *  一般URL 和 调度器 之间的映射是通过 xml 文件的，
 *   说明：调度器必须为每个用户建立并保存一个简单的状态机，当请求来的时候，调度器获取当前的状态，用它判断将要运行的正确的动作，如果运行成功，就显示与下一状态相关的视图
 *      调度器还必须处理xml状态数据，当我们看到一个action属性的时候，我们会通过加载名为name 的Action类把它转换为java  类； name 是action 的属性名字
 * @Auther: gjt
 * @Date: 2024/9/8 10:08
 */
public class WorkFlowDispatcher implements Dispatcher {

    // xml期望的标记
    private static final String WORKFLOW_TAG = "workflow";
    private static final String STATE_TAG = "state";
    private static final String NAME_ATTR = "name";
    private static final String ACTION_ATTR = "action";
    private static final String VIEW_ATTR = "viewURI";

    // 查找行动类的地方(也就是接口的地方)
    private static final String ACTION_PREFIX = "j2EE.dispatcher.";

    // 工作流状态的内部模式
    class State{
        protected String name;
        protected Action action;
        protected String viewUri;
    }

    // 当前状态和状态列表
    private State[] states;
    private int currentState;

    // 初始化后由控制器调用
    @Override
    public void setContext(ServletContext context) throws IOException {
        InputStream is = context.getResourceAsStream("xml/LanguageWorkflow.xml");
        try {
            states = parseXML(is);
        } catch (Exception e) {
            throw new IOException(e.getMessage());
        }
        currentState = 0;
    }

    // 解析一个xml 文件
    private State[] parseXML(InputStream is) throws Exception {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        Document document = documentBuilder.parse(is);

        // 查找工作流元素

        NodeList workflow = document.getElementsByTagName(WORKFLOW_TAG);// 相当于找出 workflow 标签
        Node item = workflow.item(0);

        // 查找所有状态
        NodeList states = document.getElementsByTagName(STATE_TAG);
        State[] stateList = new State[states.getLength()];

        // 读取状态信息
        for (int i = 0; i < stateList.length; i++) {
            stateList[i] = new State();
            Element curState = (Element)states.item(i);
            stateList[i].name = curState.getAttribute(NAME_ATTR);
            stateList[i].viewUri = curState.getAttribute(VIEW_ATTR);

            // 将行动名转化为类实例
            String action = curState.getAttribute(ACTION_ATTR);
            if(!StringUtils.isEmpty(action)){
                Class<?> aclass = Class.forName(ACTION_PREFIX + ACTION_PREFIX);
                stateList[i].action = (Action) aclass.newInstance();
            }
        }
        return stateList;
    }

    // 选择下一个状态
    @Override
    public String getNextPage(HttpServletRequest request, ServletContext context) {
        State state = states[currentState];
        if ((state == null) || state.action.performAction(request, context)) {
            if(currentState < states.length -1){
                state = states[++currentState];
            }else {
                currentState = 0;
                state = states[currentState];
            }
        }
        return state.viewUri;
    }
}
